package puzzle.view;


import puzzle.helper.PhotoComponent;
import puzzle.helper.PhotoRescaled;
import puzzle.model.*;

import java.awt.*;
import java.awt.event.*;
import java.text.SimpleDateFormat;
import javax.swing.*;
import javax.swing.border.Border;

import java.util.ArrayList;
import java.util.List;


// This class opens a main window of the game with a given photo cut into pieces.
// We can then swap pieces to move them to their right places.
public class PlayPuzzleGui extends WindowAdapter{

   private JFrame f;
   private JTextField tf;
   private JPanel pSouth;
   
   private PuzzleModel pm;
   private String recordFileName;
   private String imagePath;
   private int xCoordinate;
   private int yCoordinate;
   private String playerName;

   private List<PhotoComponent> properList = new ArrayList<PhotoComponent>();
   private List<PhotoComponent> randomList = new ArrayList<PhotoComponent>();
   
   private Timer stopWatch;
   private int same;
   private int swaps;


   public PlayPuzzleGui(PuzzleModel pm, String recordFileName, String imagePath, 
                        int xCoordinate, int yCoordinate, String playerName) {
       
      this.pm = pm;
      this.recordFileName = recordFileName;
      this.imagePath = imagePath;
      this.xCoordinate = xCoordinate;
      this.yCoordinate = yCoordinate;
      this.playerName = playerName;

      initializeListVariables();
      launchFrame();
      
   }
   

   // Initialize properList and randomList variables.
   private void initializeListVariables(){
       
       List<PhotoComponent> helperList = new ArrayList<PhotoComponent>();
       MouseClickedHandler mouseClickedHandler = new MouseClickedHandler();

      // Generate list of image pieces in the wright order.
      // That is in the order in which they appear on the photo.
      // First piece being top-left corner and subsequent moving to bottom-right corner.
      for (int j=1; j<=yCoordinate; j++) {
          for (int i=1; i<=xCoordinate; i++) {
             PhotoComponent pc = new PhotoComponent(imagePath, xCoordinate, yCoordinate, i, j);
             pc.addMouseListener(mouseClickedHandler);
             properList.add(pc);
             helperList.add(pc);
          }
      }

      // Generate list of image pieces in the random order.
      // Where not a single piece being on the right place.
      while (helperList.size() > 2) {
          
          int max = helperList.size();
          int randomNumber = (int)(Math.random()*max);
          PhotoComponent randomImage = helperList.get(randomNumber);

          PhotoComponent properImage = properList.get(randomList.size());
          if ( randomImage.equals(properImage) ) {
              helperList.remove(randomNumber);
              int secondRandomNumber = (int)( Math.random()*(max-1) );
              PhotoComponent secondRandomImage = helperList.get(secondRandomNumber);
              randomList.add(secondRandomImage);
              helperList.set(secondRandomNumber, randomImage);
          } else {
              randomList.add(randomImage);
              helperList.remove(randomNumber);
          }
          
      }
       
      int firstRandomNumber = (int)(Math.random()*2);
      PhotoComponent firstRandomImage = helperList.get(firstRandomNumber);
      helperList.remove(firstRandomNumber);
      PhotoComponent secondRandomImage = helperList.get(0);
      PhotoComponent firstProperImage = properList.get(randomList.size());
      PhotoComponent secondProperImage = properList.get(randomList.size()+1);
      if ( firstRandomImage.equals(firstProperImage) || secondRandomImage.equals(secondProperImage) ) {
          randomList.add(secondRandomImage);
          randomList.add(firstRandomImage);
          helperList.remove(0);
      } else {
          randomList.add(firstRandomImage);
          randomList.add(secondRandomImage);
          helperList.remove(0);
      }    
                   
   }

   
   private void launchFrame() {

       initializeFrameComponents();
       
       f = new JFrame("Puzzle - game");
       f.add(tf, BorderLayout.NORTH);
       f.add(pSouth, BorderLayout.CENTER);
       f.pack();
       f.setResizable(false);
       f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
       f.setVisible(true);
       f.addWindowListener(this);
       
   }  

   
   private void initializeFrameComponents(){
       
      tf = new JTextField();
      tf.setEditable(false);

      // Double check if all image pieces are on wrong places.
      swaps = 0;
      same = 0;                                                           
      for (int i = 0; i<properList.size(); i++) {
          if( properList.get(i).equals(randomList.get(i)) ) {
              same = same + 1;
          }
      }
      
      final long startTime = System.currentTimeMillis();      
      stopWatch = new Timer( 100, new ActionListener(){
          public void actionPerformed(ActionEvent event){
              SimpleDateFormat sdf = new SimpleDateFormat("mm.ss");
              long time = (System.currentTimeMillis() - startTime) ;
              tf.setText("Swaps: " + swaps + "  Elements: " + same +  "/" + xCoordinate*yCoordinate + 
                         "  Time: " + sdf.format(time));
          }
      });
      stopWatch.start();
      
      pSouth=new JPanel();
      pSouth.setLayout(new GridLayout(yCoordinate, xCoordinate));
      for (PhotoComponent printedImage : randomList) {
          pSouth.add(printedImage);
      }
      
   }
   

   class MouseClickedHandler extends MouseAdapter{
           
           PhotoComponent currentImage = null;
           PhotoComponent previousImage = null;
           boolean firstClick = true;           

       @Override
       public void mouseClicked(MouseEvent e) {

           currentImage = (PhotoComponent)e.getSource();

           // first click on a piece sets a border around it.
           if(previousImage==null) {

               if(firstClick) {
                   firstClick = false;
               }
               Border blueBorder = null;
               blueBorder = BorderFactory.createLineBorder(Color.BLUE, 2);
               currentImage.setBorder(blueBorder);

               pSouth.repaint();

               previousImage = currentImage;
               currentImage = null;

           // Double click on the same piece piece removes the border around it.
           } else if ( randomList.indexOf(previousImage)  == randomList.indexOf(currentImage) ) {
               
               Border noBorder = null;
               previousImage.setBorder(noBorder);
               pSouth.repaint();

               previousImage = null;
               currentImage = null;

           // Two succesive clicks on different pieces swaps them.
           } else {
               
               Border noBorder = null;
               previousImage.setBorder(noBorder);

               int previousPosition = randomList.indexOf(previousImage);
               int currentPosition = randomList.indexOf(currentImage);
               randomList.set(previousPosition, currentImage);
               randomList.set(currentPosition, previousImage);
               for (PhotoComponent printedImage : randomList) {
                   pSouth.add(printedImage);
               }
               
               previousImage = null;
               currentImage = null;
               swaps = swaps + 1;
               same = 0;
               for (int i = 0; i<properList.size(); i++) {
                   if( properList.get(i).equals(randomList.get(i)) ) {
                       same = same + 1;
                   }
               }
               
               // Finally, if all the pieces are on their right places game ends.
               // Proper photo replaces pieces so that no more swaps are possible.
               // Check for new records is being made.
               // If there are new records they are being saved.
               // Records lists for the given photo are being retrieved.
               // New records lists are passed to be displayed.
               if(properList.equals(randomList)) {
                   
                   stopWatch.stop();                   
                   properList.clear();
                   randomList.clear();
                   
                   String[] text = tf.getText().split(" ");
                   String timeString = text[text.length-1];
                   double timeTaken = Double.parseDouble(timeString);                   
                                   
                   tf.setText("Swaps: " + swaps + "   Elements: " + same +  "/" + xCoordinate*yCoordinate
                               + "   Time: " + timeString);

                   PhotoRescaled photo = new PhotoRescaled(imagePath);
                   pSouth.removeAll();                   
                   f.remove(pSouth);
                   f.add(photo);

                   Record newMoveRecord = pm.tryRecord(recordFileName, playerName, swaps, "move");
                   Record newTimeRecord = pm.tryRecord(recordFileName, playerName, timeTaken, "time");
                   List<Record> moveRecordsList = pm.getAllMoveRecords(recordFileName);
                   List<Record> timeRecordsList = pm.getAllTimeRecords(recordFileName);
                   String noOfElements = xCoordinate + "x" + yCoordinate;
                   StartPageGui.displayRecords(imagePath, moveRecordsList, timeRecordsList, noOfElements, newMoveRecord, newTimeRecord);
                                      
               }

           }

       }

   }   
   
   
   // Do some clear up when this window is being closed.
   @Override
   public void windowClosed(WindowEvent e) {
       pSouth.removeAll();
       randomList.clear();
       properList.clear();
       
   }
   

}